#pragma once

#include <iostream>

#include "event.hpp"
#include "position.hpp"

enum CreatureType
{
    CT_NONE,
    CT_WOLF,
    CT_SHEEP,
    CT_GRASS
};

class Creature
{
protected:
    static int g_index;

    int m_id = -1;

    CreatureType m_type = CT_NONE;

    Position m_position;

    int m_age = 0;

    bool m_gender = true;

    int m_hp = 100; // 暂时不使用

    int m_hunger = 0;

    int m_sight = 3;

public:
    Creature()
    {
        m_id = g_index++;
    }

    virtual ~Creature()
    {
    }

    int id()
    {
        return m_id;
    }

    CreatureType type()
    {
        return m_type;
    }

    const Position &position()
    {
        return m_position;
    }

    /**
     * @brief 生物根据各自的规则进行行动
     *
     * @return Event* 返回非空表示发生了事件，返回nullptr表示没发生事件
     */
    virtual Event *run() = 0;

    /**
     * @brief 吃掉另一个生物, 基类简单的实现，子类可以多态
     *
     * @param c
     */
    virtual void eat(Creature *c);

    /**
     * @brief 是否可以吃掉另一个生物，不同的类需要具体实现
     *
     * @param c 用来被判定是否可以吃掉的生物
     * @return true
     * @return false
     */
    virtual bool can_eat(Creature *c) = 0;

    /**
     * @brief 移动到指定位置
     *
     * @param p
     */
    void move_to(const Position &p);

    /**
     * @brief 觅食，与Nature互相依赖，在cpp中实现
     *
     */
    Event *foraging();

    Event *foraging(const Position &p);

    /**
     * @brief 生存，躲避天敌
     *
     */
    Event *survive();

    Event *stroll();

    void die();

    /**
     * @brief 将对象序列化成一个字符串，实际上不同子类应该是不同的
     *        但是现在程序中子类还没有扩展属性，所以先用基类的了
     *
     * @param str
     */
    virtual void to_string(std::string &str);

    virtual bool from_string(const std::string &str);
};
